home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 2 / The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO / os2 / killem.zip / KILLEM.C < prev    next >
Text File  |  1992-05-31  |  27KB  |  576 lines

  1. /**********************************************************************
  2.  * MODULE NAME :  killem.c               AUTHOR:  Rick Fishman        *
  3.  * DATE WRITTEN:  10-24-91                                            *
  4.  *                                                                    *
  5.  * DESCRIPTION:                                                       *
  6.  *                                                                    *
  7.  *  This program kills the specified process(s). It uses the          *
  8.  *  undocumented function DosQProcStatus to get a buffer filled with  *
  9.  *  information related to the current state of the system. It then   *
  10.  *  performs the following using the buffer:                          *
  11.  *                                                                    *
  12.  *  1. Get the relevant process information for all active pids into  *
  13.  *     an array.                                                      *
  14.  *  2. Go thru the module information table. For each module found,   *
  15.  *     see if the module name matches those given on the command      *
  16.  *     line. If so, compare its module reference number against all   *
  17.  *     module reference numbers associated with the active pids. If   *
  18.  *     any match, issue a DosKillProcess against the matching pids.   *
  19.  *                                                                    *
  20.  * UPDATES:                                                           *
  21.  *                                                                    *
  22.  *   5/21/92 - increased buffer to 32k from 16k because of Trap D     *
  23.  *             on LAN.                                                *
  24.  *                                                                    *
  25.  *   5/21/92 - changed compare of process name to buffer so that if   *
  26.  *             'e' is specified on command line, processes that end   *
  27.  *             in 'e' will not be killed.                             *
  28.  *                                                                    *
  29.  **********************************************************************/
  30.  
  31.  
  32. /*********************************************************************/
  33. /*------- Include relevant sections of the OS/2 header files --------*/
  34. /*********************************************************************/
  35.  
  36. #define INCL_DOSERRORS
  37. #define INCL_DOSPROCESS
  38.  
  39. /**********************************************************************/
  40. /*----------------------------- INCLUDES -----------------------------*/
  41. /**********************************************************************/
  42.  
  43. #include <os2.h>
  44. #include <process.h>
  45. #include <stdarg.h>
  46. #include <stdio.h>
  47. #include <string.h>
  48. #include <stdlib.h>
  49. #include "procstat.h"
  50.  
  51. /*********************************************************************/
  52. /*------------------- APPLICATION DEFINITIONS -----------------------*/
  53. /*********************************************************************/
  54.  
  55. #define COPYRIGHT_INFO         "KillEm.exe, 32-bit, Version 2.0\n"             \
  56.                                "Copyright (c) Code Blazers, Inc 1991. All "    \
  57.                                "rights reserved.\n"
  58.  
  59. #define USAGE_INFO             "\nUsage: KillEm processname processname ...\n"
  60.  
  61. #define OUT_OF_MEMORY_MSG      "\nOut of memory!\n"
  62.  
  63. #define BUFFER_SIZE             0x8000   //** 5/21/92 changed to 32k
  64.  
  65. /**********************************************************************/
  66. /*---------------------------- STRUCTURES ----------------------------*/
  67. /**********************************************************************/
  68.  
  69. typedef struct _ACTIVEPID           // INFO ON AN ACTIVE PROCESS
  70. {
  71.     USHORT  hModRef;                // It's module reference handle
  72.     PID     pid;                    // It's Process Id
  73.  
  74. } ACTIVEPID, *PACTIVEPID;
  75.  
  76.  
  77. /**********************************************************************/
  78. /*----------------------- FUNCTION PROTOTYPES ------------------------*/
  79. /**********************************************************************/
  80.  
  81. INT    main             ( INT argc, PSZ szArg[] );
  82. VOID   KillEm           ( USHORT usProcessesToKill );
  83. INT    CompareActivePids( const void *pActivePid1, const void *pActivePid2 );
  84. BOOL   ShouldBeKilled   ( PSZ szProcessName, USHORT usProcessesToKill );
  85. VOID   FindAndKill      ( PMODINFO pmi );
  86. ULONG  KillProcess      ( PID pid, PSZ szProcessName );
  87. ULONG  Init             ( INT argc, PSZ szArg[] );
  88. ULONG  CopyProcessName  ( PSZ szProcessName, INT iArrayIndex );
  89. VOID   UpCaseNames      ( PMODINFO pmi );
  90. ULONG  BuildActivePidTbl( PPROCESSINFO ppi );
  91. VOID   Term             ( ULONG ulExitCode, INT iProcNameEntries );
  92.  
  93. /**********************************************************************/
  94. /*------------------------ GLOBAL VARIABLES --------------------------*/
  95. /**********************************************************************/
  96.  
  97. USHORT      usActiveProcesses;      // Number of active processes
  98.  
  99. ACTIVEPID   *aActivePid;            // Array of active processes
  100.  
  101. PSZ         *pszProcess;            // Array of command-line process names
  102.  
  103. PBUFFHEADER pbh;                    // Pointer to buffer header structure
  104.  
  105. /**********************************************************************/
  106. /*------------------------------ MAIN --------------------------------*/
  107. /*                                                                    */
  108. /*  MAIN DRIVER FOR PROGRAM.                                          */
  109. /*                                                                    */
  110. /*  INPUT: number of command-line arguments,                          */
  111. /*         command-line argument array                                */
  112. /*                                                                    */
  113. /*  1. Perform program initialization which will issue the            */
  114. /*     DosQProcStatus call and obtain the buffer of information.      */
  115. /*  2. Use the buffer to kill processes that match the names given    */
  116. /*     on the command-line.                                           */
  117. /*  3. Perform program termination.                                   */
  118. /*                                                                    */
  119. /*  OUTPUT: nothing                                                   */
  120. /*                                                                    */
  121. /*--------------------------------------------------------------------*/
  122. /**********************************************************************/
  123. INT main( INT argc, PSZ szArg[] )
  124. {
  125.     USHORT usProcessesToKill = argc - 1;
  126.     ULONG ulExitCode = Init( argc, szArg );
  127.  
  128.     if( ulExitCode == NO_ERROR )
  129.         KillEm( usProcessesToKill );
  130.  
  131.     Term( ulExitCode, usProcessesToKill );
  132.  
  133.     return 0;
  134. }
  135.  
  136. /**********************************************************************/
  137. /*------------------------------ KillEm ------------------------------*/
  138. /*                                                                    */
  139. /*  FIND PROCESSES NAMED ON COMMAND-LINE AND KILL THEM                */
  140. /*                                                                    */
  141. /*  INPUT: number of processes to attempt to kill                     */
  142. /*                                                                    */
  143. /*  1. Get the address of the beginning of the module info section.   */
  144. /*  2. For each module information block, check if this is one's      */
  145. /*     module name matches any process names given on the command     */
  146. /*     line. If it does, kill all active pids whose module handle     */
  147. /*     matches its module handle.                                     */
  148. /*                                                                    */
  149. /*  OUTPUT: nothing                                                   */
  150. /*                                                                    */
  151. /*--------------------------------------------------------------------*/
  152. /**********************************************************************/
  153. VOID KillEm( USHORT usProcessesToKill )
  154. {
  155.     PMODINFO pmi = pbh->pmi;
  156.  
  157.     while( pmi )
  158.     {
  159.         if( ShouldBeKilled( pmi->szModName, usProcessesToKill ) )
  160.             FindAndKill( pmi );
  161.  
  162.         pmi = pmi->pNext;
  163.     }
  164. }
  165.  
  166. /**********************************************************************/
  167. /*------------------------- ShouldBeKilled ---------------------------*/
  168. /*                                                                    */
  169. /*  DETERMINE WHETHER OR NOT WE SHOULD KILL THIS PROCESS.             */
  170. /*                                                                    */
  171. /*  INPUT: process name,                                              */
  172. /*         number of processes we are attempting to kill              */
  173. /*                                                                    */
  174. /*  1. For each process name given on the command line, see if it     */
  175. /*     is a substring of the process name passed as a parameter.      */
  176. /*     The passed module name could be a fully qualified file name.   */
  177. /*                                                                    */
  178. /*  OUTPUT: TRUE if we should kill it, FALSE if not                   */
  179. /*                                                                    */
  180. /*--------------------------------------------------------------------*/
  181. /**********************************************************************/
  182. BOOL ShouldBeKilled( PSZ szProcessName, USHORT usProcessesToKill )
  183. {
  184.     BOOL            fProcessFound = FALSE;
  185.     PSZ             szFound;
  186.     register USHORT usIdx;
  187.  
  188.     for( usIdx = 0; usIdx < usProcessesToKill; usIdx++ )
  189.     {
  190.         //** 5/21/92 bug fix
  191.  
  192.         if( (szFound = strstr( szProcessName, pszProcess[ usIdx ] )) &&
  193.             ( szFound == szProcessName || *(szFound - 1) == '\\' ) )
  194.         {
  195.             fProcessFound = TRUE;
  196.  
  197.             break;
  198.         }
  199.     }
  200.  
  201.     return fProcessFound;
  202. }
  203.  
  204. /**********************************************************************/
  205. /*--------------------------- FindAndKill ----------------------------*/
  206. /*                                                                    */
  207. /*  FIND ALL PROCESSES FOR A MODULE HANDLE AND KILL THEM              */
  208. /*                                                                    */
  209. /*  INPUT: pointer to module info block                               */
  210. /*                                                                    */
  211. /*  1. For each active pid, match it's module handle against the      */
  212. /*     module handle of the passed module information block. If it    */
  213. /*     matches, kill that process.                                    */
  214. /*                                                                    */
  215. /*  NOTE: The active array table is sorted in ascending module handle */
  216. /*        order.                                                      */
  217. /*                                                                    */
  218. /*  OUTPUT: nothing                                                   */
  219. /*                                                                    */
  220. /*--------------------------------------------------------------------*/
  221. /**********************************************************************/
  222. VOID FindAndKill( PMODINFO pmi )
  223. {
  224.     USHORT         usKilled = 0;
  225.     register INT   i;
  226.  
  227.     for( i = 0; i < usActiveProcesses; i++ )
  228.     {
  229.         if( aActivePid[ i ].hModRef > pmi->hMod )
  230.             break;
  231.  
  232.         if( aActivePid[ i ].hModRef == pmi->hMod )
  233.             if( KillProcess( aActivePid[ i ].pid, pmi->szModName ) == NO_ERROR )
  234.                 usKilled++;
  235.     }
  236.  
  237.     if( !usKilled )
  238.         printf( "\nCould not find PID for %s!\n", pmi->szModName );
  239. }
  240.  
  241. /**********************************************************************/
  242. /*--------------------------- KillProcess ----------------------------*/
  243. /*                                                                    */
  244. /*  KILL A PROCESS BY PID                                             */
  245. /*                                                                    */
  246. /*  INPUT: process id,                                                */
  247. /*         process name                                               */
  248. /*                                                                    */
  249. /*  1. Issue a DosKillProcess for the passed process id.              */
  250. /*                                                                    */
  251. /*  OUTPUT: return code from DosKillProcess                           */
  252. /*                                                                    */
  253. /*--------------------------------------------------------------------*/
  254. /**********************************************************************/
  255. ULONG KillProcess( PID pid, PSZ szProcessName )
  256. {
  257.     ULONG ulRetCode = DosKillProcess( DKP_PROCESS, pid );
  258.  
  259.     if( ulRetCode )
  260.     {
  261.         if( ulRetCode != ERROR_INVALID_PROCID )
  262.             printf( "\nFound %s (pid %u) but DosKillProcess failed (RC=%u)",
  263.                     szProcessName, pid, ulRetCode );
  264.     }
  265.     else
  266.         printf( "\nFound %s (pid %u) and Killed it", szProcessName, pid );
  267.  
  268.     fflush( stdout );
  269.  
  270.     return ulRetCode;
  271. }
  272.  
  273. /**********************************************************************/
  274. /*------------------------------ Init --------------------------------*/
  275. /*                                                                    */
  276. /*  PERFORM PROGRAM INITIALIZATION                                    */
  277. /*                                                                    */
  278. /*  INPUT: number of command-line arguments,                          */
  279. /*         command-line argument array                                */
  280. /*                                                                    */
  281. /*  1. Print copyright notice.                                        */
  282. /*  2. If no process names were specified on the command line, exit.  */
  283. /*  3. Allocate memory for an array of pointers to process name       */
  284. /*     strings. We will use this array during the main program loop   */
  285. /*     to identify process names to kill.                             */
  286. /*  4. Allocate memory for each string in the array.                  */
  287. /*  5. Copy the process names from the command line into the memory   */
  288. /*     we just allocated.                                             */
  289. /*  6. Alocate memory for the output from DosQProcStatus.             */
  290. /*  7. Make the DosQProcStatus call.                                  */
  291. /*  8. Uppercase the names in the module information section to make  */
  292. /*     string compares easier during main program logic.              */
  293. /*  9. Build an array of information related to active processes.     */
  294. /*                                                                    */
  295. /*  OUTPUT: exit code                                                 */
  296. /*                                                                    */
  297. /*--------------------------------------------------------------------*/
  298. /**********************************************************************/
  299. ULONG Init( INT argc, PSZ szArg[] )
  300. {
  301.     ULONG   ulExitCode = NO_ERROR;
  302.     USHORT  usPszArraySize = (argc - 1) * sizeof( PSZ );
  303.  
  304.     (void) printf( COPYRIGHT_INFO );
  305.  
  306.     if( argc > 1 )
  307.     {
  308.         // Allocate memory for the array of ASCIIZ process names passed on the
  309.         // command line. We can't just use the commandline because we may need
  310.         // to add .EXE to the end of the process name. So we allocate our own
  311.         // array of strings so we have enough room for that extension if
  312.         // necessary.
  313.  
  314.         pszProcess = (PSZ *) malloc( usPszArraySize );
  315.  
  316.         if( pszProcess )
  317.         {
  318.             register INT i;
  319.  
  320.             (void) memset( pszProcess, 0, usPszArraySize );
  321.  
  322.             for( i = 1; i < argc && ulExitCode == NO_ERROR; i++ )
  323.                 ulExitCode = CopyProcessName( szArg[ i ], i - 1 );
  324.         }
  325.  
  326.         if( ulExitCode == NO_ERROR )
  327.             if( !(pbh = malloc( BUFFER_SIZE )) )
  328.             {
  329.                 printf( OUT_OF_MEMORY_MSG );
  330.  
  331.                 ulExitCode = ERROR_NOT_ENOUGH_MEMORY;
  332.             }
  333.  
  334.         if( ulExitCode == NO_ERROR )
  335.         {
  336.             USHORT usRetCode = DosQProcStatus( pbh, BUFFER_SIZE );
  337.  
  338.             if( usRetCode )
  339.             {
  340.                 printf( "\nDosQProcStatus failed. RC: %u.", usRetCode );
  341.  
  342.                 ulExitCode = (ULONG) usRetCode;
  343.             }
  344.         }
  345.  
  346.         if( ulExitCode == NO_ERROR )
  347.         {
  348.             UpCaseNames( pbh->pmi );
  349.  
  350.             ulExitCode = BuildActivePidTbl( pbh->ppi );
  351.         }
  352.     }
  353.     else
  354.     {
  355.         printf( USAGE_INFO );
  356.  
  357.         ulExitCode = ERROR_INVALID_PARAMETER;
  358.     }
  359.  
  360.     return ulExitCode;
  361. }
  362.  
  363. /**********************************************************************/
  364. /*-------------------------- CopyProcessName -------------------------*/
  365. /*                                                                    */
  366. /*  COPY A COMMANDLINE PROCESS NAME TO OUR ARRAY OF PROCESS NAMES.    */
  367. /*                                                                    */
  368. /*  INPUT: pointer to commandline process name,                       */
  369. /*         index into process-name array                              */
  370. /*                                                                    */
  371. /*  1. Allocate memory for the process-name string.                   */
  372. /*  2. Copy the process name from the command line into the memory    */
  373. /*     we just allocated. If the process name has no .EXE extension,  */
  374. /*     force it on.                                                   */
  375. /*                                                                    */
  376. /*  OUTPUT: exit code                                                 */
  377. /*                                                                    */
  378. /*--------------------------------------------------------------------*/
  379. /**********************************************************************/
  380. ULONG CopyProcessName( PSZ szProcessName, INT iArrayIndex )
  381. {
  382.     ULONG   ulExitCode = NO_ERROR;
  383.     USHORT  usStringLen;
  384.     PCH     pchExtension;
  385.  
  386.     // Calculate memory needed for the process name. Make sure the
  387.     // memory size is large enough to include an EXE extension,
  388.     // especially if we need to add one.
  389.  
  390.     usStringLen = strlen( szProcessName ) + 1;
  391.  
  392.     if( !(pchExtension = strchr( szProcessName, '.' )) )
  393.         usStringLen += 4;
  394.  
  395.     pszProcess[ iArrayIndex ] = malloc( usStringLen );
  396.  
  397.     if( pszProcess[ iArrayIndex ] )
  398.     {
  399.         (void) strcpy( pszProcess[ iArrayIndex ], szProcessName );
  400.  
  401.         (void) strupr( pszProcess[ iArrayIndex ] );
  402.  
  403.         if( !pchExtension )
  404.             (void) strcat( pszProcess[ iArrayIndex ], ".EXE" );
  405.     }
  406.     else
  407.     {
  408.         printf( OUT_OF_MEMORY_MSG );
  409.  
  410.         ulExitCode = ERROR_NOT_ENOUGH_MEMORY;
  411.     }
  412.  
  413.     return ulExitCode;
  414. }
  415.  
  416. /**********************************************************************/
  417. /*---------------------------- UpCaseNames ---------------------------*/
  418. /*                                                                    */
  419. /*  MAKE PROCESS NAMES IN MODULE TABLE UPPERCASE.                     */
  420. /*                                                                    */
  421. /*  INPUT: pointer to module table                                    */
  422. /*                                                                    */
  423. /*  1. Upcase all names in the module information section to make it  */
  424. /*     easy on the module name string compare.                        */
  425. /*                                                                    */
  426. /*  OUTPUT: nothing                                                   */
  427. /*                                                                    */
  428. /*--------------------------------------------------------------------*/
  429. /**********************************************************************/
  430. VOID UpCaseNames( PMODINFO pmi )
  431. {
  432.     while( pmi )
  433.     {
  434.         (void) strupr( pmi->szModName );
  435.  
  436.         pmi = pmi->pNext;
  437.     }
  438. }
  439.  
  440. /**********************************************************************/
  441. /*------------------------ BuildActivePidTbl -------------------------*/
  442. /*                                                                    */
  443. /*  BUILD AN ARRAY OF ACTIVE PROCESSES USING THE PROCESS INFO SECTION */
  444. /*  OF THE DosQProcStatus BUFFER.                                     */
  445. /*                                                                    */
  446. /*  INPUT: pointer to ProcessInfo section of buffer                   */
  447. /*                                                                    */
  448. /*  1. Get a count of active processes.                               */
  449. /*  2. Allocate memory for the ActiveProcess table.                   */
  450. /*  3. Store information about each active process in the table.      */
  451. /*  4. Sort the table in ascending module number order.               */
  452. /*                                                                    */
  453. /*  OUTPUT: exit code                                                 */
  454. /*                                                                    */
  455. /*--------------------------------------------------------------------*/
  456. /**********************************************************************/
  457. ULONG BuildActivePidTbl( PPROCESSINFO ppi )
  458. {
  459.     PPROCESSINFO ppiLocal = ppi;
  460.     ULONG        ulExitCode = NO_ERROR;
  461.  
  462.     // Count the number of processes in the process info section. The process
  463.     // count in the summary record is not reliable (2/17/92 - version 6.177)
  464.  
  465.     usActiveProcesses = 0;
  466.  
  467.     while( ppiLocal->ulEndIndicator != PROCESS_END_INDICATOR )
  468.     {
  469.         usActiveProcesses++;
  470.  
  471.         // Next PROCESSINFO struct found by taking the address of the first
  472.         // thread control block of the current PROCESSINFO structure and
  473.         // adding the size of a THREADINFO structure times the number of
  474.         // threads
  475.  
  476.         ppiLocal = (PPROCESSINFO) (ppiLocal->ptiFirst+ppiLocal->usThreadCount );
  477.     }
  478.  
  479.     if( !(aActivePid = malloc( usActiveProcesses * sizeof( ACTIVEPID ) )) )
  480.     {
  481.         printf( OUT_OF_MEMORY_MSG );
  482.  
  483.         ulExitCode = ERROR_NOT_ENOUGH_MEMORY;
  484.     }
  485.     else
  486.     {
  487.         register INT i;
  488.  
  489.         for( i = 0; i < usActiveProcesses; i++ )
  490.         {
  491.             aActivePid[ i ].hModRef = ppi->hModRef;
  492.  
  493.             aActivePid[ i ].pid = (PID) ppi->pid;
  494.  
  495.             ppi = (PPROCESSINFO) (ppi->ptiFirst + ppi->usThreadCount);
  496.         }
  497.  
  498.         qsort( aActivePid, usActiveProcesses, sizeof( ACTIVEPID ),
  499.                CompareActivePids );
  500.     }
  501.  
  502.     return ulExitCode;
  503. }
  504.  
  505. /**********************************************************************/
  506. /*------------------------ CompareActivePids -------------------------*/
  507. /*                                                                    */
  508. /*  COMPARE FUNCTION FOR THE QSORT OF THE ACTIVE PID ARRAY. SORTS     */
  509. /*  THE ARRAY IN MODULE HANDLE ORDER.                                 */
  510. /*                                                                    */
  511. /*  INPUT: pointer to first element for compare,                      */
  512. /*         pointer to second element of compare                       */
  513. /*                                                                    */
  514. /*  1. Do the compare.                                                */
  515. /*                                                                    */
  516. /*  OUTPUT: < 0 means first < second                                  */
  517. /*          = 0 means first = second                                  */
  518. /*          > 0 means first > second                                  */
  519. /*                                                                    */
  520. /*--------------------------------------------------------------------*/
  521. /**********************************************************************/
  522. INT CompareActivePids( const void *pActivePid1, const void *pActivePid2 )
  523. {
  524.     if( ((PACTIVEPID)pActivePid1)->hModRef < ((PACTIVEPID)pActivePid2)->hModRef )
  525.         return -1;
  526.     else
  527.     if( ((PACTIVEPID)pActivePid1)->hModRef > ((PACTIVEPID)pActivePid2)->hModRef )
  528.         return +1;
  529.     else
  530.         return 0;
  531. }
  532.  
  533. /**********************************************************************/
  534. /*------------------------------ Term --------------------------------*/
  535. /*                                                                    */
  536. /*  PERFORM PROGRAM TERMINATION                                       */
  537. /*                                                                    */
  538. /*  INPUT: exit code,                                                 */
  539. /*         number of process names entered on the command line        */
  540. /*                                                                    */
  541. /*  1. Free the array of process name strings that we allocated       */
  542. /*     during program initialization.                                 */
  543. /*  2. Free the ActiveProcess array.                                  */
  544. /*  3. Free the buffer allocated for the DosQProcStatus output.       */
  545. /*  4. Return the exit code to the operating system.                  */
  546. /*                                                                    */
  547. /*  OUTPUT: nothing                                                   */
  548. /*                                                                    */
  549. /*--------------------------------------------------------------------*/
  550. /**********************************************************************/
  551. VOID Term( ULONG ulExitCode, INT iProcessNameEntries )
  552. {
  553.     if( pszProcess )
  554.     {
  555.         register INT i;
  556.  
  557.         for( i = 0; i < iProcessNameEntries; i++ )
  558.             if( pszProcess[ i ] )
  559.                 free( pszProcess[ i ] );
  560.  
  561.         free( pszProcess );
  562.     }
  563.  
  564.     if( aActivePid )
  565.         free( aActivePid );
  566.  
  567.     if( pbh )
  568.         free( pbh );
  569.  
  570.     DosExit( EXIT_PROCESS, ulExitCode );
  571. }
  572.  
  573. /**********************************************************************
  574.  *                       END OF SOURCE CODE                           *
  575.  **********************************************************************/
  576.